<!DOCTYPE html>
<html>
    <head>
        <meta charset='utf-8'>
        <title>ExcelispatrixV0.0008</title>
        <script src="jquery.min.js"></script>
    </head>
    <style>
        td {
            border-width: 1px;
            border-style: dotted;
        }
        td.cur {
            border: rgb(0, 14, 206) 2px solid;
        }
    </style>
    <body>

<script>
/* 我们规定以单个$为前缀命名的变量用来存放jQuery化的对象 */

/* INITDATA 可以说是世界本源了，如果没有这个东西，
    一个新用户的页面上什么也加载不出来。*/
const INITDATA = [
    ['=return "双击单元格进行编辑"','已完成'],
    ['在编辑状态下按Ctrl+Enter求值','已完成'],
    ['在编辑状态下按ESC退出编辑状态','已完成'],
    ['单元格选中打亮','已完成'],
    [`=this.css("color","#ff0000")
return "用Ctrl+上下左右键在选中格的上下左右插入行或列"`,'已实现'],
    ['=return 1+2+3',''],
    ['=return `DATA=${JSON.stringify(DATA)}`','']
]

if (!localStorage.getItem('tabledata')){
    localStorage.setItem('tabledata', JSON.stringify(INITDATA))
}

// DATA是一个二维数组，用来存放每个格子的代码
var DATA;

// $TABLE作为整个表的抓手（handle）
var $TABLE

/* $$也是个二维数组，用来存放所有从createLATTICE里生产出来的晶格对象
    妄图在【添加行】与【添加列】等操作中提供些许抓手以及便利,
    打算在LOAD的时候初始化。 */
var $$ = [];

/* $CUR 指向当前被选中的晶格对象 */
var $CUR;

//把DATA这个二维数组存到localStorage里
function SAVE() {
    localStorage.setItem('tabledata', JSON.stringify(DATA))
}

//LOAD()说加载就加载，把localstorage里的东西加载到页面上。
function LOAD() {
    DATA = JSON.parse(localStorage.getItem('tabledata'))
    $('.BIGTABLE').remove()
    $TABLE = $(`<table class="BIGTABLE"></table>`).appendTo('body')
    $$ = []
    $.each(DATA, (i, row)=>{
        $$[i] = []
        $(`<tr id="${i}"></tr>`).appendTo($TABLE)
        $.each(row, (j, col)=>{
            let $td = createLATTICE(i, j)
            $$[i][j] = $td
            $td.appendTo($('.BIGTABLE').last())
            $td.value = $td.myeval()
        })
    })
};LOAD()


//RESETALL()将把locolstorage重置成INITDATA，并重新加载页面。
function RESETALL() {
    localStorage.setItem('tabledata', JSON.stringify(INITDATA))
    $TABLE.html('')
    $$ = []
    LOAD()
}

//createLATTICE是晶格对象的工厂
function createLATTICE (i, j)
{
    var $o = $(`<td id="${i}_${j}"></td>`)
    $o.i = i
    $o.j = j

    Object.defineProperties($o,  {
        code:{
            get: function(){
                return DATA[this.i][this.j]
            },

            set: function(s){
                DATA[this.i][this.j] = s
                SAVE()
            }
        },
        value: {
            get: function(){
                return this.text()
            },
            set: function(s){
                this.html(`<pre>${s}</pre>`)
            }
        },
        left: {
            get: function() {
                return $$[this.i][this.j-1]
            },
            set: function(o) {
                $$[this.i][this.j-1] = o
            }
        },
        right: {
            get: function() {
                return $$[this.i][this.j+1]
            },
            set: function(o) {
                $$[this.i][this.j+1] = o
            }
        },
        up: {
            get: function() {
                return $$[this.i-1][this.j]
            },
            set: function(o) {
                $$[this.i-1][this.j] = o
            }
        },
        down: {
            get: function() {
                return $$[this.i+1][this.j]
            },
            set: function(o) {
                $$[this.i+1][this.j] = o
            }
        },

    })

    $o.selected = function () {
        $CUR = $o
        $CUR.addClass('cur')
    }

    $o.myeval = function() {
        let code = this.code
        if (code[0]==='=') {
            return Function(code.substr(1)).call(this)
        }
        return code
    }
    

    $o.dblclick(function(){
        var $thisTD = $o

        var OLDVALUE = $thisTD.value

        //创建一个输入区
        let $textarea = $thisTD.html(
            '<div contenteditable="true"><code></code></div>'
            ).children().first()

        $textarea[0].innerText = $thisTD.code

        $textarea.keydown(function(e){
            //ctrl+enter
            if(e.ctrlKey && e.key === 'Enter') {
                let newcode = $textarea[0].innerText

                $thisTD.code = newcode

                let newvalue = $thisTD.myeval()

                $thisTD.value = newvalue
            }

            //ESC
            if('Escape' === e.key) {
                $thisTD.code =  $textarea[0].innerText
                $thisTD.value= OLDVALUE
            }

        });

        $textarea.focus()
    })

    $o.click(function(){
        $('td.cur').removeClass('cur')
        $o.selected()
    })

    $o.insertRowUp = function() {
        console.log(`在${this.i}行的上面插入一行`)
        var i = this.i, j = this.j
        matrixInsertRow(DATA, i, DATA[i])
        SAVE();LOAD()
        $$[i+1][j].selected()
    }
    $o.insertRowDown = function() {
        console.log(`在${this.i}行的下面插入一行`)
        var i = this.i, j = this.j
        matrixInsertRow(DATA, i+1, DATA[i])
        SAVE();LOAD()
        $$[i][j].selected()
    }
    $o.insertColLeft = function() {
        console.log(`在${this.j}列的左面插入一列`)
        var i = this.i, j = this.j
        matrixInsertCol(DATA, j)
        SAVE();LOAD()
        $$[i][j+1].selected()
    }
    $o.insertColRight = function() {
        console.log(`在${this.j}列的右面插入一列`)
        var i = this.i, j = this.j
        matrixInsertCol(DATA, j+1)
        SAVE();LOAD()
        $$[i][j].selected()
    }
    return $o
}

function arrayInsert(A, i, x='') {
    /* 在数组A的第i的元素的位置插入x。
       那么，在一个二维数组中插入一列，也就是对它的每一行干一遍这个事情。*/
    A.splice(i, 0, x)
    return A
}

function makeArray(n, x=''){
    return new Array(n).fill(x)
}

function matrixInsertRow(A, i, X=undefined) {
    if(X) {
        return arrayInsert(A, i, X)
    }
    else {
        return arrayInsert(A, i, A[i])
    }
}

function matrixInsertCol(A, i, x=0) {
    A.forEach(
        row=>arrayInsert(row, i, x))
    return A
}

$('body').keydown(e=>{
    console.log(e)
    if(e.ctrlKey){
        if(e.key==="ArrowUp"){
            $CUR.insertRowUp()
        }
        if(e.key==="ArrowDown"){
            $CUR.insertRowDown()
        }
        if(e.key==="ArrowLeft"){
            $CUR.insertColLeft()
        }
        if(e.key==="ArrowRight"){
            $CUR.insertColRight()
        }
    }
    if(e.key==="ArrowUp"){

    }
    if(e.key==="ArrowDown"){
        
    }
    if(e.key==="ArrowLeft"){
        
    }
    if(e.key==="ArrowRight"){
        
    }
    
})

</script>
</body>
</html>
